#!/bin/sh
# - runtime
# - rw
# - bs
# - ioengine
# - iodepth
# - direct
# - test_size
# - nr_task
# - fallocate
# - time_based
# - raw_disk
# - invalidate
# - nr_files
# - filesize
# - io_size
# - file_service_type
# - random_distribution
# - numa_mem_policy
# - numa_cpu_nodes
# - pre_read
# - rwmixread
# - ioscheduler
# - ramp_time
# - loops
# - cpuload
# - donorname
# - test_filename
# - allow_mounted_write
# - create_only
# - run
# - thread
# - testfile

. $LKP_SRC/lib/reproduce-log.sh
. $LKP_SRC/lib/common.sh
. $LKP_SRC/lib/unit.sh
. $LKP_SRC/lib/debug.sh
. $LKP_SRC/lib/fs_ext.sh

[ -n "$test_size" ] || die "test_size must be specified for fio"

test_size=$(to_byte $test_size)
size=$((test_size / nr_task))

: "${bs:=4k}"
: "${ioengine:=sync}"
: "${runtime:=300}"
: "${rw:=write}"
: "${iodepth:=32}"
: "${direct:=0}"
: "${fallocate:=posix}"
: "${invalidate:=1}"
: "${nr_task:=1}"
: "${nr_files:=1}"
: "${filesize:=$size}"
: "${io_size:=$size}"
: "${file_service_type:=roundrobin}"
: "${random_distribution:=random}"
: "${pre_read:=0}"
: "${ioscheduler:=none}"
: "${ramp_time:=0}"
: "${loops:=0}"
: "${allow_mounted_write:=1}"
: "${create_only:=1}"
: "${thread:=0}"
: "${run:=1}"

direct=$(parse_bool $direct)
raw_disk=$(parse_bool $raw_disk)
thread=$(parse_bool $thread)
run=$(parse_bool $run)

if [ "$raw_disk" = 1 ]; then
	storages=$partitions
else
	storages=$mount_points
fi
[ -z "$storages" ] && die "storages is empty, we can't get jobs_per_storage and nr_task_remain"
for storage in $storages
do
	mnt_point=$(stat -c %m $(readlink -f $storage))
	available_storage_size=$(df -k | awk '{print $4" "$NF}' | grep $mnt_point$ | awk '{print $1}')
	[ $available_storage_size ] || die "storage $storage doesn't mounted"
	available_storage_size=$(to_byte ${available_storage_size}k)

	require_size=$test_size
	df | grep $mnt_point$ | awk '{print $1}' | grep -q /dev/pmem && require_size=$size
	[ $available_storage_size -lt $require_size ] && die "storage $storage available size: $available_storage_size < $require_size"
done

nr_storages=$(echo $storages | wc -w)
jobs_per_storage=$((nr_task / nr_storages))

nr_task_remain=$((nr_task % nr_storages))
[ "$nr_task_remain" -ne 0 ] && die "nr_task % nr_storages = $nr_task_remain"

create_task="\
[global]
bs=$bs
ioengine=$ioengine
iodepth=$iodepth
size=$size
direct=$direct
runtime=$runtime
group_reporting
"

avgs="\
nr_files
filesize
invalidate
fallocate
io_size
file_service_type
random_distribution
allow_mounted_write
create_only
ioscheduler"

for avg in $avgs
do
	value=$(eval echo $(echo '$'"$avg"))
	if [ "$value" != "none" ];then
		create_task="\
$create_task
$avg=$value"
	fi
done

if [ "$pre_read" != "none" ];then
	create_task="\
$create_task
pre_read=$(parse_bool $pre_read)"
fi

if [ "$thread" = 1 ];then
	create_task="\
$create_task
thread"
fi

params="ramp_time loops"
for param in $params; do
	param_value="$(eval echo '$'$param)"
	if [ "$param_value" != 0 ];then
		create_task="\
$create_task
$param=$param_value"
	fi
done

if parse_bool -q "$time_based"; then
	create_task="\
$create_task
time_based
"
fi

if parse_bool -q "$cpuload"; then
	create_task="
$create_task
cpuload=$cpuload
"
fi

if parse_bool -q "$donorname"; then
       create_task="
$create_task
donorname=$donorname
"
fi

[ -n "$rwmixread" ] && [ "$rw" = "randrw" ] && rwmixread_setup="rwmixread=$rwmixread"

parse_numa_mem_policy()
{
	if [ -z "$numa_mem_policy" ]; then
		__numa_mem_policy_setup="none"
	elif [ "${numa_mem_policy%:even}" != "$numa_mem_policy" ]; then
		__numa_mem_policy_mode="${numa_mem_policy%:even}"
		__numa_mem_policy_setup="even"
	else
		__numa_mem_policy_setup="orig"
	fi
}

__numa_mem_policy()
{
	__seq_no=$1

	case "$__numa_mem_policy_setup" in
		none)
		;;
		even)
			echo "numa_mem_policy=${__numa_mem_policy_mode}:$((__seq_no%nr_node))"
			;;
		orig)
			echo "numa_mem_policy=${numa_mem_policy}"
			;;
	esac
}

parse_numa_cpu_nodes()
{
	if [ -z "$numa_cpu_nodes" ]; then
		__numa_cpu_nodes_setup="none"
	elif [ "${numa_cpu_nodes%even*}" != "$numa_cpu_nodes" ]; then
		__numa_cpu_nodes_setup="even"
	else
		__numa_cpu_nodes_setup="orig"
	fi
}

__numa_cpu_nodes()
{
	__seq_no=$1

	case "$__numa_cpu_nodes_setup" in
		none)
		;;
		even)
			echo "numa_cpu_nodes=$((__seq_no%nr_node))"
			;;
		orig)
			echo "numa_cpu_nodes=${numa_cpu_nodes}"
			;;
	esac
}

parse_numa_mem_policy
parse_numa_cpu_nodes

no=0

for storage in $storages; do
	if [ "$raw_disk" = 1 ]; then
		storage_setup="filename=$storage"
	elif [ -n "$test_filename" ]; then
		storage_setup="filename=$storage/$test_filename"
	elif is_null_blk /dev/$(basename $storage); then
		storage_setup="filename=/dev/nullb0"
	elif is_mount_on_root /dev/$(basename $storage); then
		[ -d "/lkp/benchmarks/fio" ] || mkdir /lkp/benchmarks/fio
		if [ "$testfile" = 'y' ]; then
			storage_setup="\
directory=/lkp/benchmarks/fio
filename=fio_testfile_local
"
		else
			storage_setup="directory=/lkp/benchmarks/fio"
		fi
	elif [ "$testfile" = 'y' ]; then
		storage_setup="\
directory=$storage
filename=fio_testfile
"
	else
		storage_setup="directory=$storage"
	fi
        if [ "$ioengine" = "sg" ]; then
                dev_src=$(findmnt $storage -no source)
                storage_setup="filename=$dev_src\nallow_mounted_write=1"
        fi
	create_task="\
$create_task
[task_$no]
rw=$rw
$storage_setup
numjobs=$jobs_per_storage
$rwmixread_setup
name=rw_${rw}_bs_${bs}_jobname
$(__numa_mem_policy $no)
$(__numa_cpu_nodes $no)
"
	no=$((no+1))
done

echo -n "$create_task" | sed '/create_only/d' > $TMP_RESULT_ROOT/fio.task

if [ "$run" = 1 ];then
	echo -n "$create_task" | fio --output-format=json - > /dev/null
fi
